<template>
  <view class="bluetooth-container">
    <!-- 连接状态指示 -->
    <view class="status-indicator" :class="{ connected: connected }">
      <text class="status-text">{{ statusText }}</text>
      <text class="packet-status" v-if="isSending">
        发送进度: {{ sentPackets }}/{{ totalPackets }}包
      </text>
    </view>
    
    <!-- 调试信息（可选） -->
    <view class="debug-info" v-if="debugMode">
      <text>Device: {{ shortDeviceId }}</text>
      <text>Service: {{ shortServiceId }}</text>
      <text>Characteristic: {{ shortCharacteristicId }}</text>
    </view>
  </view>
</template>

<script>
export default {
  name: 'BluetoothModule',
  props: {
    targetDeviceName: String,
    debugMode: {
      type: Boolean,
      default: false
    },
    maxRetries: {
      type: Number,
      default: 3
    },
    autoConnect: {
      type: Boolean,
      default: true
    },
    packetSize: {
      type: Number,
      default: 20, // 默认每包20字节
      validator: v => v > 0 && v <= 20 // 不超过蓝牙单包限制
    },
    packetDelay: {
      type: Number,
      default: 10 // 默认包间隔10ms
    }
  },
  data() {
    return {
      // 蓝牙连接信息
      deviceId: '',
      serviceId: '',
      characteristicId: '',
      deviceName: '',
      connected: false,
      
      // 发送状态
      isSending: false,
      sentPackets: 0,
      totalPackets: 0,
      
      // 状态控制
      statusText: '未初始化',
      isOperating: false,
      retryCount: 0,
      
      // 定时器
      operationTimer: null,
      retryTimer: null,
      
      // 回调函数
      receiveCallback: null,
      errorCallback: null,
      connectCallback: null,
      
      // 特征值优先级配置
      characteristicPriority: [
        { pattern: 'FFF2', prop: 'write' },
        { pattern: 'FFE1', prop: 'notify' },
        { pattern: '0000FFE1', prop: 'notify' },
        { pattern: '00001002', prop: 'notify' },
        { pattern: '00001001', prop: 'write' }
      ]
    }
  },
  computed: {
    shortDeviceId() {
      return this.deviceId ? `${this.deviceId.slice(0, 4)}...${this.deviceId.slice(-4)}` : ''
    },
    shortServiceId() {
      return this.serviceId ? `${this.serviceId.slice(0, 4)}...${this.serviceId.slice(-4)}` : ''
    },
    shortCharacteristicId() {
      return this.characteristicId ? `${this.characteristicId.slice(0, 4)}...${this.characteristicId.slice(-4)}` : ''
    }
  },
  created() {
    if (this.autoConnect) {
      this.initBluetooth()
    }
  },
  beforeDestroy() {
    this._cleanup()
  },
  methods: {
    // ================ 公开方法 ================ //
    
    initBluetooth(deviceName = this.targetDeviceName) {
      return this._executeOperation('初始化', () => {
        return new Promise((resolve, reject) => {
          uni.openBluetoothAdapter({
            success: () => {
              this.statusText = deviceName ? `搜索${deviceName}...` : '搜索设备...'
              this._startDeviceDiscovery(deviceName)
                .then(resolve)
                .catch(reject)
            },
            fail: (err) => {
              this._handleError('初始化失败', err)
              reject(err)
            }
          })
        })
      })
    },
    
    sendData(data, isHexString = false) {
      if (this.isSending) {
        return Promise.reject(new Error('当前有数据正在发送'))
      }
      
      let hexData = isHexString ? data : this.strToHex(data)
      return this._executeOperation('发送数据', () => {
        return hexData.length <= this.packetSize * 2 
          ? this._sendSinglePacket(hexData)
          : this._sendMultiPackets(hexData)
      })
    },
    
    disconnect() {
      return this._executeOperation('断开连接', () => {
        return new Promise((resolve) => {
          if (this.deviceId && this.connected) {
            uni.closeBLEConnection({
              deviceId: this.deviceId,
              success: () => {
                this._resetState()
                this.statusText = '已断开'
                resolve()
              },
              fail: (err) => {
                this._handleError('断开连接失败', err)
                resolve() // 仍然视为成功断开
              }
            })
          } else {
            resolve()
          }
        })
      })
    },
    
    setReceiveCallback(callback) {
      this.receiveCallback = callback
    },
    
    setErrorCallback(callback) {
      this.errorCallback = callback
    },
    
    // ================ 内部方法 ================ //
    
    _executeOperation(operationName, operation) {
      if (this.isOperating) {
        return Promise.reject(new Error(`已有操作在进行中，无法执行${operationName}`))
      }
      
      this.isOperating = true
      this.statusText = `${operationName}中...`
      
      return operation()
        .finally(() => {
          this.isOperating = false
        })
    },
    
    _startDeviceDiscovery(deviceName) {
      return new Promise((resolve, reject) => {
        this.retryCount = 0
        this._discoverWithRetry(deviceName, resolve, reject)
      })
    },
    
    _discoverWithRetry(deviceName, resolve, reject) {
      this.retryCount++
      
      uni.startBluetoothDevicesDiscovery({
        success: () => {
          this.statusText = deviceName ? 
            `搜索${deviceName}中(${this.retryCount}/${this.maxRetries})...` : 
            `搜索设备中(${this.retryCount}/${this.maxRetries})...`
          
          this.operationTimer = setTimeout(() => {
            uni.stopBluetoothDevicesDiscovery()
            if (this.retryCount < this.maxRetries) {
              this._delayOperation(() => {
                this._discoverWithRetry(deviceName, resolve, reject)
              }, 1000)
            } else {
              const err = new Error('设备搜索超时')
              this._handleError('搜索失败', err)
              reject(err)
            }
          }, 8000)
          
          const listener = uni.onBluetoothDeviceFound((res) => {
            const targetDevice = deviceName ? 
              res.devices.find(d => d.name && d.name.includes(deviceName)) :
              res.devices[0]
            
            if (targetDevice) {
              listener.stop()
              clearTimeout(this.operationTimer)
              uni.stopBluetoothDevicesDiscovery()
              
              this.deviceName = targetDevice.name
              this.statusText = `连接${targetDevice.name}...`
              
              this._connectDevice(targetDevice.deviceId)
                .then(() => resolve(targetDevice))
                .catch(reject)
            }
          })
        },
        fail: (err) => {
          if (this.retryCount < this.maxRetries) {
            this._delayOperation(() => {
              this._discoverWithRetry(deviceName, resolve, reject)
            }, 1000 * this.retryCount)
          } else {
            this._handleError('搜索失败', err)
            reject(err)
          }
        }
      })
    },
    
    _connectDevice(deviceId) {
      return new Promise((resolve, reject) => {
        this.retryCount = 0
        this.deviceId = deviceId
        
        this._executeWithRetry(
          () => this._createConnection(),
          this.maxRetries,
          '连接设备'
        ).then(() => {
          return this._executeWithRetry(
            () => this._discoverServices(),
            this.maxRetries,
            '发现服务'
          )
        }).then(() => {
          return this._executeWithRetry(
            () => this._discoverCharacteristics(),
            this.maxRetries,
            '发现特征值'
          )
        }).then(() => {
          return this._executeWithRetry(
            () => this._enableNotifications(),
            this.maxRetries,
            '启用通知'
          )
        }).then(resolve).catch(reject)
      })
    },
    
    _createConnection() {
      return new Promise((resolve, reject) => {
        uni.createBLEConnection({
          deviceId: this.deviceId,
          success: () => {
            this.connected = true
            resolve()
          },
          fail: (err) => {
            this._handleError('连接失败', err)
            reject(err)
          }
        })
      })
    },
    
    _discoverServices() {
      return new Promise((resolve, reject) => {
        uni.getBLEDeviceServices({
          deviceId: this.deviceId,
          success: (res) => {
            if (res.services.length === 0) {
              reject(new Error('未找到服务'))
              return
            }
            this.serviceId = res.services[0].uuid
            resolve()
          },
          fail: (err) => {
            this._handleError('发现服务失败', err)
            reject(err)
          }
        })
      })
    },
    
    _discoverCharacteristics() {
      return new Promise((resolve, reject) => {
        uni.getBLEDeviceCharacteristics({
          deviceId: this.deviceId,
          serviceId: this.serviceId,
          success: (res) => {
            const char = this._findSuitableCharacteristic(res.characteristics)
            if (char) {
              this.characteristicId = char.uuid
              resolve()
            } else {
              const err = new Error('未找到合适的特征值')
              this._handleError('发现特征值失败', err)
              reject(err)
            }
          },
          fail: (err) => {
            this._handleError('发现特征值失败', err)
            reject(err)
          }
        })
      })
    },
    
    _enableNotifications() {
      return new Promise((resolve, reject) => {
        uni.notifyBLECharacteristicValueChange({
          deviceId: this.deviceId,
          serviceId: this.serviceId,
          characteristicId: this.characteristicId,
          state: true,
          success: () => {
            this._setupValueChangeListener()
            this.statusText = `已连接: ${this.deviceName}`
            resolve()
          },
          fail: (err) => {
            this._handleError('启用通知失败', err)
            reject(err)
          }
        })
      })
    },
    
    _setupValueChangeListener() {
      uni.onBLECharacteristicValueChange((res) => {
        const value = this.ab2hex(res.value)
        if (this.receiveCallback) {
          this.receiveCallback(value)
        }
      })
    },
    
    _sendSinglePacket(hexData) {
      return new Promise((resolve, reject) => {
        const buffer = this.hexToArrayBuffer(hexData)
        
        uni.writeBLECharacteristicValue({
          deviceId: this.deviceId,
          serviceId: this.serviceId,
          characteristicId: this.characteristicId,
          value: buffer,
          success: () => {
            if (this.debugMode) {
              console.log('发送成功:', hexData)
            }
            resolve()
          },
          fail: (err) => {
            if (this.debugMode) {
              console.error('发送失败:', hexData, err)
            }
            this._handleError('发送失败', err)
            reject(err)
          }
        })
      })
    },
    
    _sendMultiPackets(hexData) {
      return new Promise((resolve, reject) => {
        this.isSending = true
        this.totalPackets = Math.ceil(hexData.length / (this.packetSize * 2))
        this.sentPackets = 0
        
        const sendNextPacket = (index) => {
          if (index >= this.totalPackets) {
            this.isSending = false
            resolve()
            return
          }
          
          const start = index * this.packetSize * 2
          const end = Math.min(start + this.packetSize * 2, hexData.length)
          const packetData = hexData.slice(start, end)
          
          this._sendSinglePacket(packetData)
            .then(() => {
              this.sentPackets++
              if (this.debugMode) {
                console.log(`包 ${index + 1}/${this.totalPackets} 发送成功`)
              }
              setTimeout(() => sendNextPacket(index + 1), this.packetDelay)
            })
            .catch(err => {
              this.isSending = false
              this._handleError(`包 ${index + 1}/${this.totalPackets} 发送失败`, err)
              reject(err)
            })
        }
        
        sendNextPacket(0)
      })
    },
    
    _findSuitableCharacteristic(characteristics) {
      for (const item of this.characteristicPriority) {
        const found = characteristics.find(c => 
          c.uuid.indexOf(item.pattern) !== -1 && c.properties[item.prop]
        )
        if (found) return found
      }
      return null
    },
    
    _executeWithRetry(operation, maxRetries, operationName) {
      return new Promise((resolve, reject) => {
        let attempts = 0
        
        const execute = () => {
          attempts++
          this.statusText = `${operationName}中(${attempts}/${maxRetries})...`
          
          operation()
            .then(resolve)
            .catch(err => {
              if (attempts < maxRetries) {
                this._delayOperation(execute, 500 * attempts)
              } else {
                reject(err)
              }
            })
        }
        
        execute()
      })
    },
    
    _delayOperation(operation, delay) {
      return new Promise(resolve => {
        this.retryTimer = setTimeout(() => {
          operation().then(resolve)
        }, delay)
      })
    },
    
    _handleError(context, error) {
      console.error(`${context}:`, error)
      this.statusText = `${context}: ${error.message}`
      if (this.errorCallback) {
        this.errorCallback(context, error)
      }
    },
    
    _resetState() {
      this.deviceId = ''
      this.serviceId = ''
      this.characteristicId = ''
      this.deviceName = ''
      this.connected = false
      this.isSending = false
      this.sentPackets = 0
      this.totalPackets = 0
      this.retryCount = 0
    },
    
    _cleanup() {
      this._clearTimers()
      this.disconnect()
    },
    
    _clearTimers() {
      if (this.operationTimer) clearTimeout(this.operationTimer)
      if (this.retryTimer) clearTimeout(this.retryTimer)
      this.operationTimer = null
      this.retryTimer = null
    },
    
    // ================ 工具方法 ================ //
    
    /**
     * ArrayBuffer转16进制字符串
     * @param {ArrayBuffer} buffer
     * @returns {String}
     */
    ab2hex(buffer) {
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        bit => ('00' + bit.toString(16)).slice(-2)
      )
      return hexArr.join('')
    },
    
    /**
     * 16进制字符串转ArrayBuffer
     * @param {String} hexString
     * @returns {ArrayBuffer}
     */
    hexToArrayBuffer(hexString) {
      if (hexString.length % 2 !== 0) {
        throw new Error('Hex string length must be even')
      }
      
      const bytes = new Uint8Array(hexString.length / 2)
      for (let i = 0; i < hexString.length; i += 2) {
        bytes[i / 2] = parseInt(hexString.substr(i, 2), 16)
      }
      return bytes.buffer
    },
    
    /**
     * 字符串转16进制
     * @param {String} str
     * @returns {String}
     */
    strToHex(str) {
      let hex = ''
      for (let i = 0; i < str.length; i++) {
        hex += str.charCodeAt(i).toString(16).padStart(2, '0')
      }
      return hex
    },
    
    /**
     * 16进制转字符串
     * @param {String} hex
     * @returns {String}
     */
    hexToStr(hex) {
      let str = ''
      for (let i = 0; i < hex.length; i += 2) {
        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16))
      }
      return str
    }
  }
}
</script>

<style scoped>
.bluetooth-container {
  padding: 10rpx;
}

.status-indicator {
  padding: 8rpx 16rpx;
  border-radius: 20rpx;
  background-color: #f0f0f0;
  margin-bottom: 10rpx;
}

.status-indicator.connected {
  background-color: #e1f5fe;
}

.status-text {
  font-size: 28rpx;
  color: #333;
}

.packet-status {
  font-size: 24rpx;
  color: #666;
  margin-left: 15rpx;
}

.debug-info {
  font-size: 24rpx;
  color: #888;
  display: flex;
  flex-direction: column;
}
</style>